#include "utility.h"
#include <QTextCodecPlugin>
#include <QByteArray>
#include <QLocale>
#include <osg/Drawable>
#include <osg/Geode>
#include <osg/Node>
#include <osg/Group>
#include <osg/AnimationPath>
#include <assert.h>
#include <osg\Geometry>
//#include <sstream>

bool _boolIsOutdoor;

QTextCodec* ChineseTextCodec::m_pChineseCodec = NULL;

void ChineseTextCodec::SetChineseCodecPluginObject(QObject* plugin)
{
      QTextCodecPlugin* pCodecPlugin = dynamic_cast<QTextCodecPlugin*>(plugin);
	  if(pCodecPlugin)
	  {
		  m_pChineseCodec = pCodecPlugin->createForName("GBK");
	  }
}

QTextCodec* ChineseTextCodec::GetChineseCodec()
{
     if (m_pChineseCodec==NULL)
     {
		 m_pChineseCodec = QTextCodec::codecForName("GBK");
     }
	 return m_pChineseCodec;
}

std::string ChineseTexttoStdstring(const QString& strChinese,bool bConvertOnlyInChineseLanguageSystem)
{
	if(bConvertOnlyInChineseLanguageSystem)
	{
		if(QLocale::system().language() != QLocale::Chinese)
		{
			return strChinese.toStdString();
		}
	}

	QTextCodec *codec = ChineseTextCodec::GetChineseCodec();
	if (codec)
	{
		QByteArray gbkString = codec->fromUnicode(strChinese);
		std::string strstd = gbkString.data();
		return strstd;
	}
	else
	{
        return strChinese.toStdString();
	}
}

void setOsgNodeMask(osg::Node* node,unsigned int mask)
{
	osg::Geode* geode = node->asGeode();
	if(geode)
	{
		geode->setNodeMask(mask);
		return;
	}
	QList<osg::Group*> listgroup;
	osg::Group* pgroup = node->asGroup();
	if(pgroup)
	{
		pgroup->setNodeMask(mask);
        listgroup.push_back(pgroup);
	}
	while(listgroup.size()>0)
	{
		osg::Group* pFrontGroup = listgroup.front();
		listgroup.pop_front();
		int nNode = pFrontGroup->getNumChildren();
		for(int i=0; i<nNode; i++)
		{
			node = pFrontGroup->getChild(i);
			osg::Geode* geode = node->asGeode();
			if(geode)
			{
				geode->setNodeMask(mask);
			}
			else
			{
				osg::Group* pgroup = node->asGroup();
				if(pgroup)
				{
					pgroup->setNodeMask(mask);
					listgroup.push_back(pgroup);
				}
			}			
		}
	}
}

int getTextWidth(int textsize,const QString& text)
{
	int size = 0;
	for(int i = 0;i<text.size();i++)
	{
		QChar car = text.data()[i];
		if(car > 0x80)
		{
			size = size+2;
		}
		else
		{
			size++;
		}
	}
	return size*textsize/2;
}

void formatText(const QString& qtext,int charactercount,QVector<QString>& returntext)
{
	QString text = qtext;
	text.replace("\r\n","\n");
	int textsize = 0;
	for(int i = 0;i<text.size();i++)
	{
		QChar car = text.data()[i];
		if(car > 0x80)
		{
			textsize = textsize+2;
		}
		else
		{
			textsize++;
		}
	}
	if(textsize > charactercount)
	{
		QString returntext1 = "";
		textsize = 0;
		for(int i = 0;i<text.size();i++)
		{
			QChar car = text.data()[i];
			if(car > 0x80)
			{
				textsize = textsize+2;
			}
			else
			{
				textsize++;
			}
			if(car == '\n')
			{
				if(returntext1!="")
				{
					returntext.push_back(returntext1);
					textsize = 0;
					returntext1 = "";
				}
			}
			else
			{
				returntext1.append(car);
				if(textsize + 2 >= charactercount)
				{
					returntext.push_back(returntext1);
					textsize = 0;
					returntext1 = "";
				}
			}
		}
		if(returntext1!="")
			returntext.push_back(returntext1);
	}
	else
	{
		returntext.push_back(text);
	}
}

void foundChildStateSet(osg::Node* node,QVector<osg::ref_ptr<osg::Material>>& vec)
{
	if(!node->asGroup())
	{
		if(node->getStateSet()!=NULL)
			vec.push_back((osg::Material*)node->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL));
		if(node->asGeode())
		{
			osg::Geode* geode = node->asGeode();
			osg::Geode::DrawableList list = geode->getDrawableList();
			for(int i=0;i<list.size();++i)
			{
				if(list.at(i)->getStateSet()!=NULL)
					vec.push_back((osg::Material*)list.at(i)->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL));
			}
		}
		return;
	}
	QList<osg::Group*> listgroup;
	osg::Group* group = node->asGroup();
	listgroup.push_back(group);
	if(node->getStateSet()!=NULL)
		vec.push_back((osg::Material*)node->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL));
	while(listgroup.size()>0)
	{
		osg::Group* frontgroup = listgroup.front();
		listgroup.pop_front();
		int num = frontgroup->getNumChildren();
		for(int j=0; j<num;++j)
		{
			node = frontgroup->getChild(j);
			if(!node->asGroup())
			{
				if(node->getStateSet()!=NULL)
					vec.push_back((osg::Material*)node->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL));
				if(node->asGeode())
				{
					osg::Geode* geode = node->asGeode();
					osg::Geode::DrawableList list = geode->getDrawableList();
					for(int i=0;i<list.size();++i)
					{
						if(list.at(i)->getStateSet()!=NULL)
							vec.push_back((osg::Material*)list.at(i)->getStateSet()->getAttribute(osg::StateAttribute::MATERIAL));
					}
				}
			}
			else
				listgroup.push_back(node->asGroup());		
		}
	}
}

//std::wstring s2ws(const std::string& s)
//{
// int len;
// int slength = (int)s.length() + 1;
// len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
// wchar_t* buf = new wchar_t[len];
// MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
// std::wstring r(buf);
// delete[] buf;
// return r.c_str();
//}

void composeNumberFromHandL(int& num,int hv,int lv)
{
	QVector<int> heightvec;
	QVector<int> lowvec;
	num = 0;
	int h = hv;
	while(h>=2)
	{
		heightvec.push_back(h%2);
		h = h/2;
	}
	heightvec.push_back(h);
	int l = lv;
	while(l>=2)
	{
		lowvec.push_back(l%2);
		l = l/2;
	}
	lowvec.push_back(l);
	for(int i=0;i<heightvec.size();++i)
	{
		num = num + heightvec.at(i)*pow(2.0f,(16+i));
	}
	for(int i=0;i<lowvec.size();++i)
	{
		num = num + lowvec.at(i)*pow(2.0f,i);
	}
}

void splitNumberToHandL(int num,int& h,int& l)
{
	QVector<int> vec;
	h = 0;
	l = 0;
	int n = num;
	while(n>=2)
	{
		vec.push_back(n%2);
		n = n/2;
	}
	vec.push_back(n);
	int size = vec.size();
	if(size>8)
	{
		for(int i=0;i<8;++i)
		{
			l = l+ vec.at(i)*pow(2.0f,i);
		}
		for(int i=8;i<size;++i)
		{
			h = h+ vec.at(i)*pow(2.0f,i-16);
		}
	}
	else
	{
		for(int i=0;i<size;++i)
		{
			l = l+ vec.at(i)*pow(2.0f,i);
		}
	}
}

bool pointInTriangle(const osg::Vec2& tripoint1,const osg::Vec2& tripoint2,
								const osg::Vec2& tripoint3,const osg::Vec2& point)
{
	float z = (point.x() - tripoint1.x())*(tripoint2.y() - tripoint1.y()) - (tripoint2.x() - tripoint1.x())*(point.y() - tripoint1.y());
	z = z/((tripoint3.x() - tripoint1.x())*(tripoint2.y() - tripoint1.y())- (tripoint2.x() - tripoint1.x())*(tripoint3.y() - tripoint1.y()));
	float y = (point.x() - tripoint1.x() - (tripoint3.x() - tripoint1.x())*z)/(tripoint2.x() - tripoint1.x());
	float x = 1 - y - z;
	if(x>0 && y>0 && z>0)
		return false;
	else
		return true;
}

bool shapeIsCounterclockwise(std::vector<osg::Vec3> vertexvector)
{
	int resultvalue = 0;
	for(int i=0;i<vertexvector.size()-1;++i)
	{
		osg::Vec3 p3;
		if(i+2==vertexvector.size())
			p3 = vertexvector.at(0);
		else
			p3 = vertexvector.at(i+2);
		osg::Vec3 v1 = vertexvector.at(i+1) - vertexvector.at(i);
		osg::Vec3 v2 = p3 - vertexvector.at(i+1);
		osg::Vec3 result = osg::Vec3(v1.x(),v1.y(),0)^osg::Vec3(v2.x(),v2.y(),0);
		if(result.z()>0)
			resultvalue++;
		else
			resultvalue--;
	}
	return resultvalue>0;
}

QString getPreOrderString(int order)
{
	QString os = QString::number(order);
	while(os.size()<6)
	{
		os = "0"+os;
	}
	return os;
}

void getVUValue(osg::Vec3 normal ,osg::Vec3& mu,osg::Vec3& mv)
{
	normal.normalize();
	if(abs(normal.x())>=abs(normal.y()))
	{
		mu.x() = normal.z();
		mu.y() = 0;
		mu.z() = normal.x()*-1;
	}
	else
	{
		mu.x() = 0;
		mu.y() = normal.z();
		mu.z() = normal.y()*-1;
	}
	mv = normal^mu;
}

//std::vector<osg::Vec3> getExpandPointVec(const osg::Vec3 centerpoint,float radius,int facenum
//																 ,const osg::Vec3 mu,const osg::Vec3 mv)
//{
//	std::vector<osg::Vec3> mvec;
//	for(int i=0;i<facenum;i++)
//	{
//		float angle = i*osg::PI*2/facenum;
//		osg::Vec3 point = centerpoint+mu*(radius*cos(angle)) + mv*(radius*sin(angle));
//		mvec.push_back(point);
//	}
//	return mvec;
//}

double conversionDMS_TO_D(int d,int m,double s)
{
	double result = d;
	double v = m*60+s;
	result = result + v/3600.00;
	return result;
}

double conversionDM_TO_D(int d,double m)
{
	double result = d;
	result = result + m/60.00;
	return result;
}

void conversionD_TO_DMS(double dv,int& d,int& m,double& s)
{
	d = dv;
	m = (dv-d)*3600/60;
	double v = dv-d-m/60.0;
	s = v*3600.0;
}

COREBASE_EXPORT void getTaperedCurve(int startheight,int endheight,int speed,float radianspeed,
	float a,QVector<osg::Vec3>& returnvec)
{
	osg::Vec3 point;
	int height = startheight;
	int t = (endheight - startheight)/speed;
	for(int i=0;i<t;++i)
	{
		point.z() = height+speed*i;
		point.x() = (point.z()/tan(a))*cos(radianspeed*i);
		point.y()=(point.z()/tan(a))*sin(radianspeed*i);
		returnvec.push_back(point);
	}
}

//void sortNum(std::vector<float>& vec,int start,int end)
//{
//	if(start>=end)
//		return;
//	float key = vec.at(start);
//	int i=start;
//	int j=end;
//	while(i!=j)
//	{
//		while(i!=j)
//		{
//			if(vec.at(j)<key)
//			{
//				float ival = vec[i];
//				vec[i] = vec[j];
//				vec[j] = ival;
//				break;
//			}
//			j--;
//		}
//		while(i!=j)
//		{
//			if(vec.at(i)>key)
//			{
//				float jval = vec[j];
//				vec[j] = vec[i];
//				vec[i] = jval;
//			}
//			i++;
//		}
//	}
//	sortNum(vec,start,i-1);
//	sortNum(vec,i+1,end);
//}
//
//void sortNumVec3(std::vector<osg::Vec3>& vec,int index,int start,int end)
//{
//	if(start>=end)
//		return;
//	float key = vec.at(start)._v[index];
//	int i=start;
//	int j=end;
//	while(i!=j)
//	{
//		while(i!=j)
//		{
//			if(vec.at(j)._v[index]<key)
//			{
//				osg::Vec3 ival = vec[i];
//				vec[i] = vec[j];
//				vec[j] = ival;
//				break;
//			}
//			j--;
//		}
//		while(i!=j)
//		{
//			if(vec.at(i)._v[index]>key)
//			{
//				osg::Vec3 jval = vec[j];
//				vec[j] = vec[i];
//				vec[i] = jval;
//			}
//			i++;
//		}
//	}
//	sortNumVec3(vec,index,start,i-1);
//	sortNumVec3(vec,index,i+1,end);
//}

int intersectionTestSphereWithSegment(double segx1, double segy1, double segz1,
	double segx2, double segy2, double segz2,double sx, double sy, double sz, double r,
	double *ix, double *iy, double *iz)
{
	const double i = segx2 - segx1;
	const double j = segy2 - segy1;
	const double k = segz2 - segz1;
	const double a = i * i + j * j + k * k;
	const double b = 2.0 * ( i * ( segx1 - sx ) + j * ( segy1 - sy ) + k * ( segz1 - sz) );
	const double c = sx * sx + sy * sy + sz * sz + segx1 * segx1 + segy1 * segy1 + segz1 * segz1
		- 2.0 * ( sx * segx1 + sy * segy1 + sz * segz1 ) - r * r;
	const double d = b * b - 4 * a * c;
	if (d < 0 || d == 0.0 && a == 0.0)
		return 0;
	if (d > -0.0000001 && d < 0.0000001){
		const double t = ( (a > -0.0000001 && a < 0.0000001 ) ? 0.0 : -b / (2.0 * a) );
		ix[0] = ix[1] = segx1 + t * i;
		iy[0] = iy[1] = segy1 + t * j;
		iz[0] = iz[1] = segz1 + t * k; 
		return 1;
	}
	else{
		const double t0 = ( (a > -0.0000001 && a < 0.0000001 ) ? 0.0 : (-b + sqrt(d)) / (2.0 * a) );
		const double t1 = ( (a > -0.0000001 && a < 0.0000001 ) ? 0.0 : (-b - sqrt(d)) / (2.0 * a) );
		if (t0 < t1){
			ix[0] = segx1 + t0 * i;
			iy[0] = segy1 + t0 * j;
			iz[0] = segz1 + t0 * k;
			ix[1] = segx1 + t1 * i;
			iy[1] = segy1 + t1 * j;
			iz[1] = segz1 + t1 * k;
		}
		else{
			ix[0] = segx1 + t1 * i;
			iy[0] = segy1 + t1 * j;
			iz[0] = segz1 + t1 * k;
			ix[1] = segx1 + t0 * i;
			iy[1] = segy1 + t0 * j;
			iz[1] = segz1 + t0 * k;
		}
		return 2;
	}  
}

float getEarthDistance(double lng1, double lat1, double lng2, double lat2)
{
	double lng1radian = lng1 * osg::PI / 180.0;
	double lat1radian = lat1 * osg::PI / 180.0;
	double lng2radian = lng2 * osg::PI / 180.0;
	double lat2radian = lat2 * osg::PI / 180.0;

	double a = lat1radian - lat2radian;
	double b = lng1radian - lng2radian;
	float s = 2 * asin(sqrt(pow(sin(a/2),2) + 
		cos(lat1radian)*cos(lat2radian)*pow(sin(b/2),2)));
	s = s * 6378137;
	return s;
}

float getEarthDistanceLNG(double lng1, double lat1, double lng2, double lat2)
{
	double lng1radian = lng1 * osg::PI / 180.0;
	double lng2radian = lng2 * osg::PI / 180.0;
	double b = lng2radian - lng1radian;
	float s = b*6378137;
	return s;
}

float getEarthDistanceLAT(double lng1, double lat1, double lng2, double lat2)
{
	float s1 = getEarthDistance(lng1,lat1,lng2,lat2);
	float s2 = getEarthDistanceLNG(lng1,lat1,lng2,lat2);
	float s = sqrt(pow(s1,2) - pow(s2,2));
	s = lat2<lat1?s*-1:s;
	return s;
}